package com.yz.bi.mq;

import com.rabbitmq.client.Channel;
import com.yz.bi.constant.CommonConstant;
import com.yz.bi.manager.AiManager;
import com.yz.model.entity.bi.Chart;
import com.yz.bi.service.BiService;
import com.yz.common.constant.MQConstants;
import jakarta.annotation.Resource;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * Created With IntelliJ IDEA.
 * Descriptions:
 * User:Mr.Du
 * Date:2024/4/10
 * Time:22:41
 */
@Slf4j
@Component
public class BiMessageConsumer {

    @Resource
    private BiService biService;

    @Resource
    private AiManager aiManager;

    /**
     * 监听BI队列，处理接收到的消息。
     *
     * @param message 接收到的消息内容，预期为图表的ID。
     * @param channel AMQP通道，用于消息确认和异常处理。
     * @param deliveryTag 消息的传递标签，用于消息确认。
     * @throws Exception 处理过程中任何异常都会被抛出。
     */
    @SneakyThrows
    @RabbitListener(queues = {MQConstants.BI_QUEUE_NAME}, ackMode = "MANUAL")
    public void receiveMessage(String message, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag){
        log.info("receive message: {}", message);

        // 检查消息是否为空
        if(StringUtils.isBlank(message)){
            log.info("消息不能为空");
            channel.basicNack(deliveryTag, false, false);
            throw new RuntimeException("消息不能为空");
        }
        List<Chart> list = biService.list();
        log.info("图表列表长度：{}", list.size());
        // 尝试将消息解析为图表ID，并查询图表信息
        Long chartId = Long.parseLong(message);
        Chart chart = biService.getById(chartId);
        log.info("图表信息：{}", chart);
        // 图表不存在时的处理
        if(chart == null){
            log.info("图表不存在");
            channel.basicNack(deliveryTag, false, false);
            throw new RuntimeException("图表不存在");
        }

        // 更新图表状态为运行中
        Chart updateChart = Chart.builder()
                .status("running")
                .id(chartId)
                .build();
        boolean update = biService.updateById(updateChart);
        if(!update){
            log.info("更新图表状态失败");
            channel.basicNack(deliveryTag, false, false);
            this.handleChartUpdateError(chartId, "更新图表状态失败");
            throw new RuntimeException("更新图表状态失败");
        }

        // 调用AI管理器生成图表
        String result = aiManager.doChat(CommonConstant.BI_MODE_ID, this.buildUserInput(chart));
        String[] res = result.split("【【【【【");
        if(res.length < 2){
            channel.basicNack(deliveryTag, false, false);
            throw new RuntimeException("AI 生成错误");
        }

        // 解析并更新图表的生成图表和结果信息
        String genChart = res[1];
        String genResult = res[2];
        if(StringUtils.isBlank(genChart) || StringUtils.isBlank(genResult)){
            channel.basicNack(deliveryTag, false, false);
            throw new RuntimeException("AI 生成错误");
        }
        log.info("AI 生成结果：{}", result);

        // 更新图表状态失败的处理
        Chart updateChartResult = Chart.builder()
                .status("succeed")
                .genChart(genChart)
                .genResult(genResult)
                .id(chartId)
                .build();
        chart.setGenChart(genChart);
        chart.setGenResult(genResult);
        chart.setStatus("succeed");
        update = biService.updateById(updateChartResult);
        if(!update){
            log.info("更新图表状态失败");
            channel.basicNack(deliveryTag, false, false);
            this.handleChartUpdateError(chartId, "更新图表状态失败");
            throw new RuntimeException("更新图表状态失败");
        }

        // 消息处理成功，进行确认
        channel.basicAck(deliveryTag, false);
    }

    /**
     * 构建用户输入的字符串信息。
     * 该方法根据提供的图表对象，提取图表的目标、类型和数据，然后构建一个包含分析需求和原始数据的字符串。
     *
     * @param chart 包含图表相关信息的对象，包括目标、类型和数据。
     * @return 返回一个字符串，内容包括分析需求和原始数据。
     */
    private String buildUserInput(Chart chart){
        // 提取图表的目标、类型和数据
        String goal = chart.getGoal();
        String chartType = chart.getChartType();
        String csvData = chart.getChartData();

        // 根据图表类型组合用户目标信息
        String userGoal = null;
        if(StringUtils.isNotBlank(chartType)){
            userGoal = goal + "，请使用" + chartType;
        }

        // 构造用户输入信息
        StringBuilder sb = new StringBuilder();
        sb.append("分析需求：").append(userGoal).append("\n");
        // 原始数据
        sb.append("原始数据：").append(csvData).append("\n");
        return sb.toString();

    }


    /**
     * 处理图表更新错误的情况。
     *
     * @param chartId 图表的ID，用于标识需要更新的图表。
     * @param execMessage 更新执行过程中遇到的错误信息。
     * 该方法尝试将指定图表的状态更新为"failed"，并记录错误执行信息。
     * 如果更新失败，则记录错误日志。
     */
    private void handleChartUpdateError(Long chartId, String execMessage){
        // 创建一个新的Chart实例并设置为失败状态，准备更新
        Chart chart = Chart.builder().build();
        chart.setId(chartId);
        chart.setStatus("failed");
        chart.setExecMessage(execMessage);

        // 尝试更新图表状态并获取更新结果
        boolean update = biService.save(chart);
        if(!update){
            // 如果更新失败，记录错误日志
            log.error("更新图表失败状态失败, " + chartId + ", " + execMessage);
        }
    }
}
